home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / display.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  10.0 KB  |  396 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/display.c,v 2.1 90/10/04 18:23:57 melissa Exp $";
  10. #endif
  11.  
  12. /*
  13.  * display.c - support for the mm display command
  14.  */
  15.  
  16. #include "mm.h"
  17. #include "cmds.h"
  18. #include "message.h"
  19. #include "parse.h"
  20.  
  21. FILE *more_pipe_open();
  22. extern mail_msg *current;
  23.  
  24. static keywrd disp_swits[] = {
  25.     { "expand", 0, (keyval) CMD_EXPAND },
  26. };
  27.  
  28. static keytab disp_tab = { (sizeof(disp_swits)/sizeof(keywrd)), disp_swits };
  29. static fdb disp_swi_fdb = { _CMSWI, 0, NULL, (pdat) &disp_tab, NULL, "/expand",
  30.                 NULL };
  31.  
  32. cmd_display(n)
  33. int n;
  34. {
  35.     pval pv;
  36.     fdb *used;
  37.     int which;
  38.     int expand;
  39.     FILE *pipe;
  40.     extern int use_crt_filter_always;
  41.  
  42.     noise("message field");
  43.     parse(fdbchn(&hdr_cmd_fdb, &disp_cmd_fdb, &disp_swi_fdb, nil),&pv, &used);
  44.     which = (int) pv._pvkey;
  45.     expand = FALSE;
  46.     if (which == CMD_EXPAND) {
  47.     expand = TRUE;
  48.     parse(fdbchn(&hdr_cmd_fdb, &disp_cmd_fdb, nil),&pv, &used);
  49.     which = (int) pv._pvkey;
  50.     }
  51.     confirm();
  52.     pipe = stdout;            /* default for output */
  53.     switch(which) {
  54.     case CMD_HEADER:
  55.     display_header(pipe,current,expand, FALSE);
  56.     break;
  57.     case CMD_ALL:
  58.     if (use_crt_filter_always ||
  59.         ((text_length(current) + num_headers(current)) >= cmcsb._cmrmx))
  60.         pipe = more_pipe_open(stdout);
  61.     display_msg(pipe,current,expand);
  62.     break;
  63.     case CMD_BCC:
  64.     if (current->bcc)
  65.         disp_addresses(pipe,"Bcc", current->bcc->address,
  66.                expand,true,false,true);
  67.     break;
  68.     case CMD_CC:
  69.     if (current->cc)
  70.         disp_addresses(pipe,"Cc", current->cc->address,expand,true,false,
  71.                true);
  72.     break;
  73.     case CMD_FCC:
  74.     if (current->fcc)
  75.         disp_addresses(pipe,"Fcc", current->fcc->address,
  76.                expand,true,false,false);
  77.     break;
  78.     case CMD_FROM:
  79.     maybe_disp_header(pipe,"From",current->from);
  80.     break;
  81.     case CMD_IN_REPLY_TO:
  82.     maybe_disp_header(pipe,"In-reply-to",current->in_reply_to);
  83.     break;
  84.     case CMD_REPLY_TO:
  85.     maybe_disp_header(pipe,"Reply-to",current->reply_to);
  86.     break;
  87.     case CMD_SUBJECT:
  88.     maybe_disp_header(pipe,"Subject", current->subject);
  89.     break;
  90.     case CMD_TEXT:
  91.     if (use_crt_filter_always ||
  92.         (text_length(current) >= cmcsb._cmrmx))
  93.         pipe = more_pipe_open(stdout);
  94.     display_text(pipe,current);
  95.     break;
  96.     case CMD_TO:
  97.     if (current->to)
  98.         disp_addresses(pipe,"To",current->to->address,expand,true,false,
  99.                true);
  100.     break;
  101.     case CMD_USER_HEADER:
  102.     disp_user_headers(pipe, current);
  103.     break;
  104.     }
  105.     if (pipe == stdout)            /* didn't open the pipe */
  106.     fflush(stdout);
  107.     else
  108.     more_pipe_close(pipe);
  109. }
  110.  
  111. /*
  112.  * maybe_disp_header:
  113.  * write out the header name and the body of the header, if non-zero-length
  114.  *
  115.  * Chris thinks this business of prepending "X-" to unknown headers is rude,
  116.  * if not illegal. Should we make it a user-settable option?
  117.  */
  118. int Xhack = 0;                /* 1 => prepend X- to odd headers */
  119.  
  120. maybe_disp_header(fp,name, header) 
  121. FILE *fp;
  122. char *name;
  123. headers *header;
  124. {
  125.     int prelen;
  126.     char *subj, *foldstring();
  127.  
  128.     if (header && header->string && strlen(header->string) > 0) {
  129.     prelen = strlen (name) + 2 +
  130.         ((Xhack && (header->flags&HEAD_UNKNOWN)) ? strlen("X-") : 0);
  131.     subj = foldstring (prelen, header->string);
  132.     fprintf(fp,"%s%s: %s\n",
  133.         (Xhack && (header->flags&HEAD_UNKNOWN)) ? "X-" : "",
  134.         name, subj);
  135.     free (subj);
  136.     }
  137. }
  138.  
  139. display_msg (pipe, msg, expand)
  140. FILE *pipe;
  141. mail_msg *msg;
  142. int expand;
  143. {
  144.     display_header (pipe, msg, expand, FALSE);
  145.     fputc ('\n', pipe);
  146.     display_text (pipe, msg);
  147. }
  148.     
  149. /*
  150.  * display_header:
  151.  * write out the headers (properly folded) into the message body (in a 
  152.  * temp file or pipe).
  153.  * If smail is TRUE, called by sendmail() so do not write out Bcc,
  154.  * add a Sender: field when necessary, etc.
  155.  * if expand is true, expand groups
  156.  */
  157.  
  158.  
  159. #ifdef DONT_EMIT_FROM_HEADERS
  160. int suppress_from_headers = 1;
  161. #else
  162. int suppress_from_headers = 0;
  163. #endif
  164.  
  165. display_header (pipe, msg, expand, smail)
  166. FILE *pipe;
  167. mail_msg *msg;
  168. int expand,smail;
  169. {
  170.     headers *h = msg->headers;
  171.  
  172.     if (smail && !suppress_from_headers && (msg->resent_to == NULL) &&
  173.     (msg->from == NULL || !valid_from_field(msg->from->string)))
  174.     write_sender(pipe);
  175.  
  176.     while (h) {
  177.     switch (h->type) {
  178.       case TO:
  179.       case CC:
  180.       case RESENT_TO:
  181.         if (h->address && h->address->last)
  182.         disp_addresses(pipe,h->name, h->address,expand,true,smail,
  183.                    true);
  184.         break;
  185.       case BCC:
  186.         if (!smail)            /* not for sendmail */
  187.         disp_addresses(pipe, h->name, h->address,expand,true,smail,
  188.                    true);
  189.         break;
  190.       case FCC:
  191.         if (!smail)
  192.         disp_addresses(pipe, h->name, h->address,expand,true,smail,
  193.                    false);
  194.       case KEYWORDS:
  195.         if (h->keys)
  196.         disp_keywords(pipe,h->name, h->keys);
  197.         break;
  198.         /*
  199.          * Some sites may not want us to generate the Sender: and
  200.          * From: fields.  We omit the Date: header as well, primarily
  201.          * so it won't appear after the From: header added by the
  202.          * delivery agent (it looks a little strange that way).
  203.          *
  204.          * Note that this is bad news in terms of trying to make
  205.          * the Fcc'd files look like those sent out by the mailer.
  206.          * But the Message-ID is omitted in either case, and the
  207.          * mailer may be munging the sender/recipient headers
  208.          * anyway.
  209.          */ 
  210.       case FROM:
  211.       case DATE:
  212.         if (smail && suppress_from_headers)
  213.         break;
  214.         /* fall through */
  215.       default:
  216.         maybe_disp_header (pipe, h->name, h);
  217.         break;
  218.     }
  219.     h = h->next;
  220.     }
  221. }
  222.  
  223. disp_keywords (fp, name, keys) 
  224. FILE *fp;
  225. char *name;
  226. keylist keys;
  227. {
  228.     if (keys) {
  229.     if (name)
  230.         fprintf(fp,"%s: ", name);
  231.     for(; keys && *keys; keys++)
  232.         fprintf(fp,"%s%s", *keys, *(keys+1) ? ", " : "\n");
  233.     }
  234. }
  235.  
  236. /*
  237.  * write out the body (text) of a message into a file (or pipe)
  238.  */
  239. display_text (pipe,msg)
  240. FILE *pipe;
  241. mail_msg *msg;
  242. {
  243.     if (msg->body && strlen(msg->body) > 0) {
  244.     fwrite (msg->body, sizeof(char), strlen(msg->body), pipe);
  245.     if (msg->body[strlen(msg->body) -1] != '\n')
  246.         fputc('\n',pipe);        /* and trailing newline */
  247.     }
  248. }
  249.  
  250.  
  251. /*
  252.  * text_length:
  253.  * find out how many lines the text will take on the screen, making sure
  254.  * we start and end with a newline
  255.  */
  256. int
  257. text_length (msg)
  258. mail_msg *msg;
  259. {
  260.     int len;
  261.  
  262.     if (msg->body && (len = strlen (msg->body)))
  263.     return (logical_lines (msg->body, cmcsb._cmrmx) + 
  264.         ((msg->body[0] == '\n') ? 0 : 1) +
  265.         ((msg->body[len] == '\n') ? 0 : 1));
  266.     return (0);                /* nothing */
  267. }
  268.  
  269. /*
  270.  * num_headers:
  271.  * count how many real headers are in this message (to determine about
  272.  * how many lines they'll take up)
  273.  */
  274. num_headers(msg)
  275. mail_msg *msg;
  276. {
  277.     int num = 0;
  278.     headers *h = msg->headers;
  279.  
  280.     while (h) {
  281.     switch(h->type) {
  282.     case TO:
  283.     case CC:
  284.     case BCC:
  285.     case RESENT_TO:
  286.         if (h->address && h->address->last)
  287.         num++;
  288.         break;
  289.     case KEYWORDS:
  290.         if (h->keys)
  291.         num++;
  292.         break;
  293.     default:
  294.         if (h && h->string && strlen(h->string) > 0)
  295.         num++;
  296.         break;
  297.     }
  298.     h = h->next;
  299.     }
  300.     return (num);
  301. }
  302.  
  303. disp_user_headers(fd, m)
  304. FILE *fd;
  305. mail_msg *m;
  306. {
  307.     headers *h = m->headers;
  308.  
  309.     while(h) {
  310.     if (h->type == USER_HEADERS)
  311.         fprintf(fd,"%s: %s\n",h->name,h->string);
  312.     h = h->next;
  313.     }
  314. }
  315.  
  316. /*
  317.  * foldstring:
  318.  * fold this string if it's too long to fit on one line
  319.  * whether or not it fits, malloc up the return value,
  320.  * SO IT MUST BE FREED
  321.  */
  322. char *
  323. foldstring(prefix, unfolded)
  324. int prefix;                /* how much of line used already */
  325. char *unfolded;
  326. {
  327.     char *folded, *stripped;        /* folded and unfolded versions */
  328.     int ufp;                /* unfolded str pointer (stripped) */
  329.     int fp;                /* folded string pointer */
  330.     int bp;                /* break point pointer */
  331.     int col;                /* columns used in current line */
  332.     int len;                /* malloc'ed length of folded */
  333.     int indentlen = 8;            /* amount to indent */
  334.     int firstline = TRUE;        /* first line (line with prefix) */
  335.     int i;
  336. #define MAXCOL 78
  337.  
  338.     stripped = (char *) safe_strcpy(unfolded);
  339.     stripped = (char *) stripspaces(stripped);    /* unfold to do it right */
  340.  
  341.     col = prefix;
  342.     ufp = fp = 0;
  343.     len = strlen(stripped) + 1;
  344.     folded = malloc (len);
  345.     while (stripped[ufp] != '\0') {
  346.     folded[fp++] = stripped[ufp++];
  347.     col++;
  348.     if (col == MAXCOL) {
  349.         folded = (char *) 
  350.         realloc (folded, len += (indentlen+1)); /* indent + nl */
  351.         fp--; ufp--;        /* point at last char copied */
  352.  
  353.         /* find a good spot to break line - back up to whitespace */
  354.         bp = fp;
  355.         while ((folded[bp] != ' ') && (folded[bp] != '\t') && 
  356.            (folded[bp] != '\n') && (bp > 0)) {
  357.         bp--;
  358.         }
  359.         /* did we find whitespace before we backed into the indentation? */
  360.         if (((folded[bp] == ' ') || (folded[bp] == '\t')) /* whitespace */
  361.         && (MAXCOL - (fp - bp) > (firstline ? prefix : indentlen))) {
  362.         /* backup pointers to matching locations in their strings */
  363.         ufp -= (fp - bp);    /* distance we backed up */
  364.         fp = bp;        /* both point just past whitespace */
  365.         }
  366.         else {            /* no whitespace to break at */
  367.         ++ufp; ++fp; 
  368.         while ((stripped[ufp] != ' ') && (stripped[ufp] != '\t')
  369.                && (stripped[ufp] != '\0')) {
  370.             folded[fp++] = stripped[ufp++];
  371.         }
  372.         if (firstline & (fp - bp) + indentlen <= MAXCOL) {
  373.             /* fits on next line (indentlen is less than prefix) */
  374.             /* break line: backup pointers to matching locations */
  375.             ufp -= (fp - bp + 1); /* distance we backed up */
  376.             fp = bp;        /* both point just past whitespace */
  377.         }
  378.         else {            /* break at next whitespace */
  379.             if (stripped[ufp] == '\0') /* end of string - done */
  380.             break;
  381.             bp = fp;        /* prepare to put newline here */
  382.         }
  383.         }
  384.         folded[fp++] = '\n';    /* replace white space with newline */
  385.         ufp++;            /* skip past the whitespace */
  386.         firstline = FALSE;        /* no longer on first line */
  387.         for (i = 0; i < indentlen; i++, fp++) /* insert indentation */
  388.         folded[fp] = ' ';
  389.         col = indentlen;
  390.     }
  391.     }
  392.     folded[fp] = '\0';
  393.     free (stripped);            /* done with that */
  394.     return (folded);
  395. }
  396.